// mysql
package bootstrap

import (
	"errors"
	"fmt"
	"log"
	"os"
	"time"

	"gitee.com/copylian/lian-go.git/helper/config"

	yCfg "github.com/olebedev/config"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
	"gorm.io/gorm/schema"
)

// MysqlInstance mysql对象
type MysqlInstance struct {
	DSN string
	DB  *gorm.DB
}

// 数据库连接列表
var mysqlDbList = make(map[string]MysqlInstance)

// InitMysql 初始化mysql
func InitMysql() {
	// 获取数据库
	dbList := getDbNames("mysql")
	for _, dbname := range dbList {
		instance, err := initDbConn(dbname)
		if err == nil {
			mysqlDbList[dbname] = instance
		}
	}
}

// mysqlLogger mysql日志
func mysqlLogger() logger.Interface {
	newLogger := logger.New(
		log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer（日志输出的目标，前缀和日志包含的内容——译者注）
		logger.Config{
			SlowThreshold:             time.Second,   // 慢 SQL 阈值
			LogLevel:                  logger.Silent, // 日志级别
			IgnoreRecordNotFoundError: true,          // 忽略ErrRecordNotFound（记录未找到）错误
			Colorful:                  false,         // 禁用彩色打印
		},
	)

	return newLogger
}

// initDbConn 连接数据库
func initDbConn(dbName string) (MysqlInstance, error) {
	// 获取数据库文件
	path := fmt.Sprintf("%sconfig/%s/mysql.yml", ProjectPath(), DevEnv)

	// 获取配置
	cfg, _ := config.GetConfig(path)

	// 设置公用配置
	maxOpenConns, _ := cfg.Int("mysql." + dbName + ".maxOpenConns")
	maxIdleConns, _ := cfg.Int("mysql." + dbName + ".maxIdleConns")
	maxLifetime, _ := cfg.Int("mysql." + dbName + ".maxLifetime")
	tablePrefix, _ := cfg.String("mysql." + dbName + ".tablePrefix")
	debug, _ := cfg.Bool("mysql." + dbName + ".debug")
	charset, _ := cfg.String("mysql." + dbName + ".charset")

	// 数据库连接服务数量
	servers, err := cfg.List("mysql." + dbName + ".servers")
	if err != nil || len(servers) < 1 {
		return MysqlInstance{}, err
	}

	// 连接配置信息,默认连接第1个配置
	host, _ := yCfg.Get(servers[0], "host")
	port, _ := yCfg.Get(servers[0], "port")
	name, _ := yCfg.Get(servers[0], "db")
	user, _ := yCfg.Get(servers[0], "user")
	passwd, _ := yCfg.Get(servers[0], "passwd")

	// 拼接连接地址
	addr := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=%s&parseTime=True&loc=Local", user.(string), passwd.(string), host.(string), port.(int), name.(string), charset)

	if connTimeout, err := yCfg.Get(servers[0], "connTimeout"); err == nil {
		addr += fmt.Sprintf("&timeout=%dms", connTimeout.(int))
	}
	if readTimeout, err := yCfg.Get(servers[0], "readTimeout"); err == nil {
		addr += fmt.Sprintf("&readTimeout=%dms", readTimeout.(int))
	}
	if writeTimeout, err := yCfg.Get(servers[0], "writeTimeout"); err == nil {
		addr += fmt.Sprintf("&writeTimeout=%dms", writeTimeout.(int))
	}

	// 连接数据库配置
	db, err := gorm.Open(mysql.Open(addr), &gorm.Config{
		Logger: mysqlLogger(), // 日志
		NamingStrategy: schema.NamingStrategy{ // 表前缀
			TablePrefix:   tablePrefix,
			SingularTable: true,
		},
	})
	if err != nil {
		return MysqlInstance{}, err
	}

	// 是否开启debug
	if debug {
		db = db.Debug()
	}

	// 连接数据库
	DB, _ := db.DB()
	err = DB.Ping()
	if err != nil {
		return MysqlInstance{}, err
	}

	// 设置mysql全局信息
	if maxLifetime > 0 {
		DB.SetConnMaxLifetime(time.Duration(maxLifetime) * time.Second)
	}
	DB.SetMaxIdleConns(maxIdleConns)
	DB.SetMaxOpenConns(maxOpenConns)

	// 返回
	return MysqlInstance{fmt.Sprintf("%s:%d/%s", host.(string), port.(int), name.(string)), db}, nil
}

// GetMysqlInstance 获取数据库连接
func GetMysqlInstance(dbName string) (MysqlInstance, error) {
	if instance, ok := mysqlDbList[dbName]; ok {
		return instance, nil
	} else {
		return instance, errors.New(dbName + " db is null")
	}
}
